﻿/*
 * @author: wizardc
 */

using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace DouEditor.Utils
{
    /// <summary>
    /// 材质相关工具类
    /// </summary>
    public static class MaterialUtil
    {
        /// <summary>
        /// 清理材质上已经失效的属性
        /// Unity 的材质在切换 Shader 时会保留上一个 Shader 设置的相关信息，这么做可以方便美术同学编辑时频繁切换 Shader 不用每次都重新设置；
        /// 坏处是上一个 Shader 里的宏或者属性（如贴图）的残留，会在打 AB 包的时候就会造成冗余浪费；
        /// 比如一个材质使用 ShaderA 并设定了环境贴图，后面美术改成了 ShaderB (这里面没有环境贴图的属性)用不到这个贴图，但是这个环境贴图仍然在材质中被设定，会被作为依赖项打包；
        /// </summary>
        public static void CleanInvalidProperty(Material material)
        {
            var propertySet = new HashSet<string>();
            var shader = material.shader;
            var count = shader.GetPropertyCount();
            for (int i = 0; i < count; i++)
            {
                var name = shader.GetPropertyName(i);
                if (!propertySet.Contains(name))
                {
                    propertySet.Add(name);
                }
            }

            var modify = false;
            
            var so = new SerializedObject(material);
            var disabledShaderPasses = so.FindProperty("disabledShaderPasses");
            if (CleanMaterialSerializedProperty(disabledShaderPasses, propertySet))
            {
                modify = true;
            }
            
            var saveProp = so.FindProperty("m_SavedProperties");
            var texEnvs = saveProp.FindPropertyRelative("m_TexEnvs");
            if (CleanMaterialSerializedProperty(texEnvs, propertySet))
            {
                modify = true;
            }
            
            SerializedProperty floats = saveProp.FindPropertyRelative("m_Floats");
            if (CleanMaterialSerializedProperty(floats, propertySet))
            {
                modify = true;
            }
            
            SerializedProperty colors = saveProp.FindPropertyRelative("m_Colors");
            if (CleanMaterialSerializedProperty(colors, propertySet))
            {
                modify = true;
            }
            
            if (modify)
            {
                so.ApplyModifiedProperties();
            }
        }
        
        private static bool CleanMaterialSerializedProperty(SerializedProperty property, HashSet<string> propertySet)
        {
            bool result = false;
            for (int i = property.arraySize - 1; i >= 0; i--)
            {
                var item = property.GetArrayElementAtIndex(i);
                var first = item.FindPropertyRelative("first");
                if (first != null)
                {
                    string propertyName = first.stringValue;
                    if (!propertySet.Contains(propertyName))
                    {
                        property.DeleteArrayElementAtIndex(i);
                        result = true;
                    }
                }
            }
            return result;
        }
    }
}
